package com.xy.work.template.base.interceptor;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.xy.work.template.base.domain.LoginSecurity;
import com.xy.work.template.base.utils.RedisUtil;
import com.xy.work.template.common.constant.CacheKey;
import com.xy.work.template.base.utils.LoginJwtUtil;
import com.xy.work.template.base.domain.JsonResult;
import com.xy.work.template.base.domain.LoginUser;
import com.xy.work.template.base.utils.CommonUtil;
import com.xy.work.template.common.annotation.NotLoginRequired;
import com.xy.work.template.common.enums.CommonCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
/**
* @author niuniu
* @Date: 2021/5/14 06:13
* @Description: 登陆拦截器相关操作
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
   public static ThreadLocal<LoginUser> threadLocal = new ThreadLocal<>();
   @Value("${application.security.check}")
   private Boolean securityCheck;
   @Value("${application.security.expire}")
   private Long securityExpire;
    /**
     * 在调用控制器方法 执行方法之前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       // 如果不是映射到方法直接通过
       if (!(handler instanceof HandlerMethod)) {
           return true;
       }
       HandlerMethod handlerMethod = (HandlerMethod) handler;
       Method method = handlerMethod.getMethod();
       // 判断接口是否需要登录
       NotLoginRequired  methodAnnotation = method.getAnnotation(NotLoginRequired.class);
       if(ObjectUtil.isNotEmpty(methodAnnotation)){
           return true;
       }
       String accessToken = request.getHeader("token");
       if(StrUtil.isEmpty(accessToken)) {
           accessToken = request.getParameter("token");
       }
       if(StrUtil.isEmpty(accessToken)){
           CommonUtil.sendJsonMessage(response, JsonResult.error(CommonCodeEnum.LOGIN_EXPIRE));
           return false;
       }

       LoginUser loginUser=null;
       try {
           loginUser= LoginJwtUtil.checkJwt(accessToken);
       }catch (Exception exception){
           log.error("解析登录错误",exception);
           CommonUtil.sendJsonMessage(response,JsonResult.error(CommonCodeEnum.LOGIN_EXPIRE));
           return false;
       }
       if(ObjectUtil.isEmpty(loginUser)){
           CommonUtil.sendJsonMessage(response,JsonResult.error(CommonCodeEnum.LOGIN_EXPIRE));
           return false;
       }
       //检测当前用户是否通过安全效验
       if(securityCheck){
           String requestIpAddr=CommonUtil.getIpAddr(request);
           String deviceUnique=CommonUtil.getDeviceUnique(request);
           String refreshTokenKey =String.format(CacheKey.REFRESH_TOKEN_KEY,loginUser.getId().toString());
           if(RedisUtil.hasKey(refreshTokenKey)){
               LoginSecurity  loginSecurity=RedisUtil.getCacheObject(refreshTokenKey);
               if(loginSecurity.getIp().equals(requestIpAddr) || deviceUnique.equals(loginSecurity.getDeviceUnique())){
                   RedisUtil.setCacheObject(refreshTokenKey,loginSecurity,securityExpire.intValue(),TimeUnit.MINUTES);
               }else {
                   CommonUtil.sendJsonMessage(response,JsonResult.error(CommonCodeEnum.LOGIN_EXPIRE));
                   return false;
               }
           }
       }
       threadLocal.set(loginUser);
       return true;
   }

    /**
     * 在渲染视图之前被调用
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param modelAndView
     * @throws Exception
     */
   @Override
   public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

   }

    /**
     * 在渲染视后被调用
     * @param httpServletRequest
     * @param httpServletResponse
     * @param o
     * @param e
     * @throws Exception
     */
   @Override
   public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
       threadLocal.remove();
   }

}
